#pragma once 

#include "SPD3D11Prerequisite.h"
#include "SPD3D11RenderEnvironment.h"
#include <list>

#include "SPModule.h"

namespace SP
{
	//-----------------------------------------------------------------------


	//-----------------------------------------------------------------------
	class DLL_EXPORT SPFileBuffer
	{
	public:
		BYTE* pFileBuffer;
		int nNumByte;
	public:
		SPFileBuffer();
		void CreateBuffer( int num );
		~SPFileBuffer();
	};

	//-----------------------------------------------------------------------

	//-----------------------------------------------------------------------
	struct DistributionFloatBuffer
	{
		UINT TYPE;
		FLOAT constant;
		FLOAT max;
		FLOAT min;
	};

	//-----------------------------------------------------------------------
	struct ModuleTransformBuffer
	{
		UINT TYPE;
		XMFLOAT3 start;
		XMFLOAT3 end;

		void InitByModule( SPModuleEmitterTransform* pModule );
		SPModuleEmitterTransform* ToModule();
	};


	//-----------------------------------------------------------------------
	struct ModuleParticleFloatBuffer
	{
		UINT TYPE;
		DistributionFloatBuffer init;
		DistributionFloatBuffer start;
		DistributionFloatBuffer end;

		void InitByModule( SPModuleParticleFloat* pModule );
		SPModuleParticleFloat* ToModule();
	};

	//-----------------------------------------------------------------------
	struct ModuleParticleVectorBuffer
	{
		UINT TYPE;
		DistributionFloatBuffer initX;
		DistributionFloatBuffer initY;
		DistributionFloatBuffer initZ;

		DistributionFloatBuffer startX;
		DistributionFloatBuffer startY;
		DistributionFloatBuffer startZ;

		DistributionFloatBuffer endX;
		DistributionFloatBuffer endY;
		DistributionFloatBuffer endZ;

		void InitByModule( SPModuleParticleVector* pModule );
		SPModuleParticleVector* ToModule();
	};


	//-----------------------------------------------------------------------
	struct EmitterFileHead
	{
		UINT nByteCount;

		FLOAT fEmitterDuration;
		FLOAT fEmitterLoops;

		bool bModuleDepthStencilState;
		bool bModuleBlendState;
		bool bModuleRasterizer;

		D3D11_BLEND_DESC BlendDesc;
		D3D11_DEPTH_STENCIL_DESC DepthStencilDesc;
		D3D11_RASTERIZER_DESC RasterizerDesc;

		UINT nModuleTranform;
	};

	struct EmitterParticleFileHead
	{
		bool bProcessSpawnRate;
		bool bSort;

		bool bModulePos;		
		bool bModuleVelo;			
		bool bModuleAccel;
		bool bModuleColour;
		bool bMoudleAlpha;
		bool bModuleSize;

		FLOAT fParticleLifeTime;
		FLOAT fSpawnRate;

		ModuleParticleVectorBuffer ModulePos;
		ModuleParticleVectorBuffer ModuleVelo;
		ModuleParticleVectorBuffer ModuleAccle;
		ModuleParticleVectorBuffer ModuleColur;
		ModuleParticleFloatBuffer ModuleAlpha;
		ModuleParticleFloatBuffer ModuleSize;

		bool bTexture;
		UINT nTextureBufferSize;
	};

	struct EmitterMeshFileHead
	{
		bool bTextureMapping;
		bool bLighting;
	};

	struct ModuleBeamTermialBuffer
	{
		BOOL bCPOverLife;
		BOOL bSPOverLife;
		XMFLOAT3 vCPStart;
		XMFLOAT3 vCPEnd;
		XMFLOAT3 vSPStart;
		XMFLOAT3 vSPEnd;

		void InitByModule( SPModuleBeamTerminal* pModule );
		SPModuleBeamTerminal* ToModule();
	};

	struct ModuleBeamShaperBuffer
	{
		UINT nShapeType;
		BOOL bOverLife;
		XMFLOAT4 vStartCenterRadius;
		XMFLOAT4 vEndCenterRadius;

		void InitByModule( SPModuleBeamShape* pModule );
		SPModuleBeamShape* ToModule();
	};

	struct EmitterBeamFileHead
	{		
		UINT nNumControlPoint;
		UINT nTessellationAmount;

		BOOL bUpdatePerFrame;
		BOOL bFaceToCamera;
		BOOL bEnableNoise;
		FLOAT fWidthScale;

		FLOAT fNoiseScale;
		FLOAT fNoiseSpeed;

		bool bModuleSource;		
		bool bModuleTarget;
		bool bModuleShape;

		ModuleBeamTermialBuffer ModuleSource;
		ModuleBeamTermialBuffer ModuleTarget;
		ModuleBeamShaperBuffer ModuleShape;

		bool bTexture;
		UINT nTextureBufferSize;
	};

	struct EmitterAnimTrailFileHead
	{
		FLOAT fAnimTrailDuration;
		UINT nTessellationAmount;
		UINT nNumControlLine;
		bool bAbsHead;

		XMFLOAT3 vLeftHead;
		XMFLOAT3 vRightHead;

		bool bTexture;
		UINT nTextureBufferSize;
	};
}


namespace SP
{
	// #include "SPEmitter.h"
	class SPEmitter;
	typedef std::list<SPEmitter*> SPEmitterList;
	//-----------------------------------------------------------------------
	class DLL_EXPORT SPEmitter : public SPD3DObject
	{
	public:
		SPEmitter();
		SPEmitter( SPEmitter* archetype );
		virtual ~SPEmitter();

		void Create( SPEmitter* archetype );

		void Move( float fElapsedTime );		

		virtual void Initialize();
		virtual void Render() = 0;	
		virtual void Advance( float fElapsedTime );
		virtual void ClearModule();
		virtual void CreateFileBuffer( SPFileBuffer* );
		virtual void CreateFromFileBuffer( BYTE* );
		virtual bool SetSPModule( SPModule* pModule );

		virtual bool IsDead()
		{ 
			return m_fEmitterLoops != 0.0f && ( m_fEmitterCurrentTime > m_fEmitterDuration * m_fEmitterLoops ); 
		}

		bool IsDepthEnable()
		{
			if ( m_pModuleDepthStencilState )
				return m_pModuleDepthStencilState->IsDepthEnable();
			return true; 
		}

		void SetDuration( float fDuration ){ m_fEmitterDuration = fDuration; }
		void SetLoops( float fLoops ){ m_fEmitterLoops = fLoops; }

		void SetActorTransformMatrix( CXMMATRIX m )
		{
			XMStoreFloat4x4( &m_mActorTransformation, m );
		}
	protected:

		std::list<SPModuleEmitterTransform*>	m_EmitterTransformList;
		XMMATRIX GetTransformMatrix();

		SPModuleEmitterColour* m_pModuleEmitterColour;
		XMVECTOR GetColourVector()
		{
			if ( m_pModuleEmitterColour )
			{
				return m_pModuleEmitterColour->GetColour( m_fEmitterLife );
			}
			return XMVectorSet( 1.0f, 1.0f, 1.0f ,1.0f );
		}

		SPModuleBlendState*							m_pModuleBlendState;
		SPModuleRasterizerState*						m_pModuleRasterizerState;
		SPModuleDepthStencilState*				m_pModuleDepthStencilState;

		ID3D11BlendState*							GetBlendState();
		ID3D11RasterizerState*						GetRasterizerState();
		ID3D11DepthStencilState*					GetDepthStencilState();	

		float				m_fEmitterLife;
		float				m_fEmitterDuration;
		float				m_fEmitterCurrentTime;
		float				m_fEmitterLoops;

		bool				m_bCopy;

		XMFLOAT4X4 m_mActorTransformation;

		void	SetZero();
	};
}